#include "strategy.h"
#include <QMap>
#include <functional>

// Strategy类的构造
Strategy::Strategy(Player* player, const Cards& cards) : m_player(player), m_cards(cards)
{

}

// 制定出牌的策略
Cards Strategy::makeStrategy()
{
    // 得到当前出牌玩家的对象以及打出去的牌
    Player* pendPlayer = m_player->getPendPlayer();
    Cards pendCards = m_player->getPendCards();

    // 判断出牌的玩家是不是自己
    if (m_player == pendPlayer || pendPlayer == nullptr) {
        // 如果出牌玩家是自己，则直接出牌，没有任何限制
        return firstPlay();
    } else {
        // 如果出牌玩家不是自己就需要找比出牌玩家点数更大的牌
        PlayHand type(pendCards);
        Cards beatCards = getGreaterCards(type);
        // 找到了点数大的牌考虑是否需要出牌
        bool shouldBeat = whetherToBeat(beatCards);
        if (shouldBeat) {
            return beatCards;
        } else {
            return Cards();
        }
    }

    return Cards();
}

// 第一个出牌 firstPlay 给机器人玩家使用，考虑最先如何出牌
Cards Strategy::firstPlay()
{
    // 1. 判断玩家手中是否只剩下单一的牌型
    PlayHand hand(m_cards);
    // 如果手牌是多种混合类型牌的组合，则不能可能一下出完。如果全是一个类型的，则可以一下将手牌出完
    if (hand.getHandType() != PlayHand::Hand_Unknown) {
        return m_cards;
    }

    // 2. 不是单一类型手牌
    // （1）有无顺子的
    QVector<Cards> optimalSeq = pickOptimalSeqSingles();
    if (!optimalSeq.isEmpty()) {
        // 考虑是否适合出顺子
        int baseNum = findCardsByCount(1).size(); // 获取出顺子之前时，手牌中的单牌总数
        // 把得到的顺子从手牌中移除，并搜索出顺子之后手牌中单排的总数
        Cards saveCards = m_cards;
        saveCards.remove(optimalSeq);
        int lastNum = Strategy(m_player, saveCards).findCardsByCount(1).size();
        if (baseNum > lastNum) { // 出顺子之后，手中单牌的数量减少，则所出的顺子适合
            return optimalSeq[0]; // 随机返回一组合适的顺子
        }
    }

    bool hasPlane, hasTriple, hasPair;
    hasPlane = hasTriple = hasPair = false;
    Cards backup = m_cards;
    // (2) 有无炸弹
    QVector<Cards> bombArray = findCardType(PlayHand(PlayHand::Hand_Bomb, Card::CardPoint::Card_Begin, 0), false);
    backup.remove(bombArray);

    // (3) 有无飞机
    QVector<Cards> planeArray = Strategy(m_player, backup).findCardType(PlayHand(PlayHand::Hand_Plane, Card::Card::Card_Begin, 0), false);
    if (!planeArray.isEmpty()) {
        hasPlane = true;
        backup.remove(planeArray);
    }

    // (4) 有没有三张点数相同的牌
    QVector<Cards> seqTripleArray = Strategy(m_player, backup).findCardType(PlayHand(PlayHand::Hand_Triple, Card::CardPoint::Card_Begin, 0), false);
    if (!seqTripleArray.isEmpty()) {
        hasTriple = true;
        backup.remove(seqTripleArray);
    }

    // (5) 有没有连对
    QVector<Cards> seqPairArray = Strategy(m_player, backup).findCardType(PlayHand(PlayHand::Hand_Seq_Pair, Card::CardPoint::Card_Begin, 0), false);
    if (!seqPairArray.isEmpty()) {
        hasPair = true;
        backup.remove(seqPairArray);
    }

    if (hasPair) {
        Cards maxPair;
        for (int i = 0; i < seqPairArray.size(); ++ i) {
            // 寻找最长连对
            if (seqPairArray[i].cardCount() > maxPair.cardCount()) {
                maxPair = seqPairArray[i];
            }
        }
        return maxPair; // 返回所找到的最长连对
    }

    if (hasPlane) {
        // 1). 飞机带两个对
        bool twoPairFond = false;
        QVector<Cards> pairArray;
        for (Card::CardPoint point = Card::CardPoint::Card_3; point <= Card::CardPoint::Card_10; point = static_cast<Card::CardPoint>(point + 1)) {
            Cards pair = Strategy(m_player, backup).findSamePointCards(point, 2);
            if (!pair.isEmpty()) {
                pairArray.push_back(pair);
                if (pairArray.size() == 2) {
                    twoPairFond = true;
                    break;
                }
            }
        }
        if (twoPairFond) {
            Cards tmp = planeArray[0];
            tmp.add(pairArray);
            return tmp;
        } else {
            // 2) 飞机带两张单牌
            bool twoSingleFond = false;
            QVector<Cards> singleArray;
            for (Card::CardPoint point = Card::CardPoint::Card_3; point <= Card::CardPoint::Card_10; point = static_cast<Card::CardPoint>(point + 1)) {
                // 避免拆分其它类型的牌,只早单张的牌
                if (backup.pointCount(point) == 1) {
                    Cards single = Strategy(m_player, backup).findSamePointCards(point, 1);
                    if (!single.isEmpty()) {
                        singleArray.push_back(single);
                        if (singleArray.size() == 2) {
                            twoSingleFond = true;
                            break;
                        }
                    }
                }
            }
            if (twoSingleFond) {
                Cards tmp = planeArray[0];
                tmp.add(singleArray);
                return tmp;
            } else {
                // 3. 只有飞机
                return planeArray[0];
            }
        }
    }

    if (hasTriple) {
        // 不要把3个A或者3个2一开就出了
        if (PlayHand(seqTripleArray[0]).getCardPoint() < Card::CardPoint::Card_SJ) {
            for (Card::CardPoint point = Card::CardPoint::Card_3; point <= Card::CardPoint::Card_A; point = static_cast<Card::CardPoint>(point + 1)) {
                int pointCount = backup.pointCount(point);
                // 3带一
                if (pointCount == 1) {
                    Cards single = Strategy(m_player, backup).findSamePointCards(point, 1);
                    Cards tmp = seqTripleArray[0];
                    tmp.add(single);
                    return tmp;
                } else if (pointCount == 2) {
                    // 3带2
                    Cards pair = Strategy(m_player, backup).findSamePointCards(point, 2);
                    Cards tmp = seqTripleArray[0];
                    tmp.add(pair);
                    return tmp;
                }
            }
        }
        return seqTripleArray[0]; // 不带任何副牌，只返回3个相同的点数
    }

    // 单排或则对子
    Player* nextPlayer = m_player->getNextPlayer();
    // 下一个玩家手牌所剩无几，并且是敌对方, 尽量出大的牌压住对方
    if (nextPlayer->getCards().cardCount() == 1 && m_player->getRole() != nextPlayer->getRole()) {
        for (Card::CardPoint point = Card::CardPoint(Card::CardPoint::Card_End - 1); point >= Card::CardPoint::Card_3; point = static_cast<Card::CardPoint>(point - 1)) {
            int pointCount = backup.pointCount(point);
            if (pointCount == 1) {
                Cards single = Strategy(m_player, backup).findSamePointCards(point, 1);
                return single;
            } else if (pointCount == 2) {
                Cards pair = Strategy(m_player, backup).findSamePointCards(point, 2);
                return pair;
            }
        }
    } else {
        // 可以随意出牌
        for (Card::CardPoint point = Card::CardPoint::Card_3; point < Card::CardPoint::Card_End; point = static_cast<Card::CardPoint>(point + 1)) {
            int pointCount = backup.pointCount(point);
            if (pointCount == 1) {
                Cards single = Strategy(m_player, backup).findSamePointCards(point, 1);
                return single;
            } else if (pointCount == 2) {
                Cards pair = Strategy(m_player, backup).findSamePointCards(point, 2);
                return pair;
            }
        }
    }

    return Cards();
 }

// 得到比指定牌大的牌
Cards Strategy::getGreaterCards(PlayHand type)
{
    // 1. 出牌玩家和当前玩家不是一伙的
    Player* pendPlayer = m_player->getPendPlayer();
    // 出牌玩家与当前玩家不是一伙的，并出牌玩家手牌所剩无几
    if (pendPlayer != nullptr && pendPlayer->getRole() != m_player->getRole() && pendPlayer->getCards().cardCount() <= 3) {
        // 搜索当前玩家手牌中的炸弹
        QVector<Cards> bombs = findCardsByCount(4);
        for (int i = 0; i < bombs.size(); ++ i) {
            if (PlayHand(bombs[i]).canBeat(type)) {
                return bombs[i];
            }
        }
        // 如果手牌中没有炸弹，搜索当前玩家手中有没有王炸
        Cards sj = findSamePointCards(Card::CardPoint::Card_SJ, 1);
        Cards bj = findSamePointCards(Card::CardPoint::Card_BJ, 1);
        if (!sj.isEmpty() && !bj.isEmpty()) {   // 找到王炸
            Cards jokers;
            jokers << sj <<  bj;
            return jokers;
        }
    }

    // 2. 当前玩家和下一个玩家不是一伙的
    Player* nextPlayer = m_player->getNextPlayer();
    // 避免拆除原有顺子牌型，考虑将玩家手中最完美的一个顺子先移除手牌
    Cards remainCards = m_cards;
    remainCards.remove(Strategy(m_player, remainCards).pickOptimalSeqSingles()); // TODO : ??????

    auto beatCard = std::bind([=](const Cards& cards) {
        QVector<Cards> beatCardsArray = Strategy(m_player, cards).findCardType(type, true);
        if (!beatCardsArray.isEmpty()) { // 找到了
            // 出牌玩家与当前玩家不是一伙的，并出牌玩家手牌所剩无几，并且搜索到能够压过对方的牌
            if (m_player->getRole() != nextPlayer->getRole() && nextPlayer->getCards().cardCount() <= 2) {
                return beatCardsArray.back(); // 返回已找到压过对方的牌中最大的一组牌
            } else {
                // 出牌玩家与当前玩家是一伙的，并且搜索到能够压过对方的牌
                return beatCardsArray.front(); // 返回已找到压过对方的牌中最小的一组牌
            }
        }
        return Cards(); // 没有搜索到，则返回一个空对象
    }, std::placeholders::_1);

    Cards cs;
    if (!(cs = beatCard(remainCards)).isEmpty()) {
        return cs;
    } else {
        if (!(cs = beatCard(m_cards)).isEmpty())
            return cs;
    }

    return Cards();
    /*
    // 在移除一个完美的顺子之后，搜索玩家手牌中依然能够压过对方的牌
    QVector<Cards> beatCardsArray = Strategy(m_player, remainCards).findCardType(type, true);
    if (!beatCardsArray.isEmpty()) { // 找到了
        // 出牌玩家与当前玩家不是一伙的，并出牌玩家手牌所剩无几，并且搜索到能够压过对方的牌
        if (m_player->getRole() != nextPlayer->getRole() && nextPlayer->getCards().cardCount() <= 2) {
            return beatCardsArray.back(); // 返回已找到压过对方的牌中最大的一组牌
        } else {
            // 出牌玩家与当前玩家是一伙的，并且搜索到能够压过对方的牌
            return beatCardsArray.front(); // 返回已找到压过对方的牌中最小的一组牌
        }
    } else {
        // 在移除一个完美的顺子之后，玩家手牌中没有能够压过对方的牌
        QVector<Cards> beatCardsArray = Strategy(m_player, m_cards).findCardType(type, true);
        if (!beatCardsArray.isEmpty()) {
            // 出牌玩家与当前玩家不是一伙的，并出牌玩家手牌所剩无几，并且搜索到能够压过对方的牌
            if (m_player->getRole() != nextPlayer->getRole() && nextPlayer->getCards().cardCount() <= 2) {
                return beatCardsArray.back(); // 返回已找到压过对方的牌中最大的一组牌
            } else {
                // 出牌玩家与当前玩家是一伙的，并且搜索到能够压过对方的牌
                return beatCardsArray.front(); // 返回已找到压过对方的牌中最小的一组牌
            }
    }

    return Cards(); // 为搜索到，则返回一个空对象
    */
}

// 在有大过指定的牌时，判断是出牌还是放行，返回true ------> 出牌， 返回false ------> 放行
bool Strategy::whetherToBeat(Cards &cs)
{
    // 没有找到能够比对方大的牌
    if (cs.isEmpty()) {
        return false;
    }

    // 得到出牌玩家的对象
    Player* pendPlayer = m_player->getPendPlayer();
    if (m_player->getRole() == pendPlayer->getRole()) { // 队友出牌
        // 手里面的牌所剩无几并且是一个完整的牌型
        Cards left = m_cards;
        left.remove(cs);
        if (PlayHand(left).getHandType() != PlayHand::Hand_Unknown) {
            return true;
        }
        // 如果cs对象中的牌最小点数是2，大小王 ------> 不出牌
        Card::CardPoint basePoint = PlayHand(cs).getCardPoint();
        if (basePoint == Card::CardPoint::Card_2 || basePoint == Card::CardPoint::Card_SJ || basePoint == Card::CardPoint::Card_BJ) {
            return false;
        }

        // 如果cs对象中是炸弹 ------> 可以考虑出牌
        /*
        PlayHand pendPlayerHand(cs);
        if (pendPlayerHand.getHandType() == PlayHand::Hand_Bomb
            && m_player->getCards().cardCount() > 3
            && PlayHand(left).getHandType() != PlayHand::Hand_Plane
            && PlayHand(left).getHandType() != PlayHand::Hand_Plane_Two_Pair
            && PlayHand(left).getHandType() != PlayHand::Hand_Seq_Single
            && PlayHand(left).getHandType() != PlayHand::Hand_Seq_Pair) {
            return false;
        }
*/
    } else { // 敌方玩家
        PlayHand myHand(cs);
        // 如果是三个2带1或则带1对， 并且对方的牌还有一定数量，则不出牌（保存实力，让对方出）
        if ((myHand.getHandType() == PlayHand::Hand_Triple_Single || myHand.getHandType() == PlayHand::Hand_Triple_Pair)
            && myHand.getCardPoint() == Card::Card_2) {
            return false;
        }
        /*
        // 如果是小王或者大王，并且对方的牌还有一定数量，则不出牌（保存实力，让对方出）
        if (myHand.getHandType() == PlayHand::Hand_Single && myHand.getCardPoint() >= Card::Card_2 && pendPlayer->getCards().cardCount() >= 10) {
            return false;
        }
*/
        // 如果cs是对2, 并且出牌玩家手中牌的数量大于等于10 && 自己的牌的数量大于等5，暂时放弃出牌
        if (myHand.getHandType() == PlayHand::Hand_Pair && myHand.getCardPoint() == Card::CardPoint::Card_2
            && pendPlayer->getCards().cardCount() >= 10 && m_player->getCards().cardCount() >= 5) {
            return false;
        }
    }
    return true;
}

// 找到指定数量的扑克牌和相同点数的扑克牌，即找到count张点数为point的扑克牌
Cards Strategy::findSamePointCards(Card::CardPoint point, int count)
{
    // 1. 判断所出扑克牌的张数是否违法
    if (count < 1 || count > 4) {
        return Cards();
    }


    // 2. 所出扑克牌为大小王的情况
    if (point == Card::Card_SJ || point == Card::Card_BJ) {
        if (count > 1) {
            return Cards();
        }

        Card card;
        card.setPoint(point);
        card.setSuit(Card::Suit_Begin);
        if (m_cards.contains(card)) {
            Cards cards;
            cards.add(card);
            return cards; // 返回手牌
        }

        return Cards();
    }

    // 3. 所出牌为非大小王的情况
    int findCount = 0;
    Cards findCards;
    for (int suit = Card::CardSuit::Suit_Begin + 1; suit < Card::CardSuit::Suit_End; ++ suit) {
        Card card;
        card.setPoint(point);
        card.setSuit(static_cast<Card::CardSuit>(suit));
        if (m_cards.contains(card)) {
           findCards.add(card);
            ++ findCount;
           if (findCount == count) {
                return findCards;
            }
        }
    }

    return Cards();
}

QVector<Cards> Strategy::findCardsByCount(int count)
{
    if (count < 1 || count > 4) {
        return QVector<Cards>();
    }

    QVector<Cards> cardsArray;
    for (Card::CardPoint point = Card::CardPoint::Card_3; point < Card::CardPoint::Card_End; point = static_cast<Card::CardPoint>(point + 1)) {
        if (m_cards.pointCount(point) == count) {
            // 如果玩家手里面的牌与传入的count参数相同
            Cards cs;
            cs << findSamePointCards(point, count);
            cardsArray << cs;
        }
    }

    return cardsArray;
}

// 根据点数的范围找到牌
Cards Strategy::getRangeCards(Card::CardPoint begin, Card::CardPoint end)
{
    Cards rangeCards;
    for (Card::CardPoint point = begin; point < end; point = static_cast<Card::CardPoint>(point + 1)) {
        int count = m_cards.pointCount(point);
        Cards cs = findSamePointCards(point, count);
        rangeCards << cs;
    }
    return rangeCards;
}

// 按牌型找牌，并且指定要找到的牌是否大于指定牌的类型
QVector<Cards> Strategy::findCardType(PlayHand hand, bool beat)
{
    PlayHand::HandType type = hand.getHandType();
    Card::CardPoint point = hand.getCardPoint();
    int extra = hand.getExtra();

    // 根据beat, 确定起始点数
    // 如果beat为true，则所找的点数一定要比hand里面的点数至少大1。如果beat为false，则所找点数与hand里面的点数无关系
    Card::CardPoint beginPoint = (beat == true ? static_cast<Card::CardPoint>(point + 1) : Card::Card_3);

    switch(type) {
    case PlayHand::Hand_Single:
        return getCards(beginPoint, 1);
    case PlayHand::Hand_Pair:
        return getCards(beginPoint, 2);
    case PlayHand::Hand_Triple:
        return getCards(beginPoint, 3);
    case PlayHand::Hand_Triple_Single:
        return getTripleSingleOrPair(beginPoint, PlayHand::Hand_Single);
    case PlayHand::Hand_Triple_Pair:
        return getTripleSingleOrPair(beginPoint, PlayHand::Hand_Pair);
    case PlayHand::Hand_Plane:
        return getPlane(beginPoint);
    case PlayHand::Hand_Plane_Two_Single:
        return getPlane2SingleOr2Pair(beginPoint, PlayHand::Hand_Single);
    case PlayHand::Hand_Plane_Two_Pair:
        return getPlane2SingleOr2Pair(beginPoint, PlayHand::Hand_Pair);
    case PlayHand::Hand_Seq_Pair:
    {
        CardInfo info;
        info.begin = beginPoint;
        info.end = Card::Card_Q;
        info.number = 2;
        info.base = 3;
        info.extra = extra;
        info.beat = beat;
        info.getSeq = &Strategy::getBaseSeqPair;
        return getSepPairOrSeqSingle(info);
    }
    case PlayHand::Hand_Seq_Single:
    {
        CardInfo info;
        info.begin = beginPoint;
        info.end = Card::Card_10;
        info.number = 1;
        info.base = 5;
        info.extra = extra;
        info.beat = beat;
        info.getSeq = &Strategy::getBaseSeqSingle;
        return getSepPairOrSeqSingle(info);
    }
    case PlayHand::Hand_Bomb:
        return getBomb(beginPoint);
    default:
        return QVector<Cards>();
    }
}

// 从指定的Cards对象中挑选出满足条件的顺子
void Strategy::pickSeqSingles(QVector<QVector<Cards>> &allSeqRecord, const QVector<Cards> &seqSingle, const Cards &cards)
{
    // 1. 得到手牌中所有的顺子的组合
    QVector<Cards> allSeq = Strategy(m_player, cards).findCardType(PlayHand(PlayHand::Hand_Seq_Single, Card::CardPoint::Card_Begin, 0), false);
    if (allSeq.isEmpty()) {
        // 递归结束添加，将满足条件的顺子传递给调用者
        allSeqRecord << seqSingle;
    } else {
        // 2. 对顺子进行筛选
        Cards saveCards = cards;
        // 遍历得到所有的顺子
        for (int i = 0; i < allSeq.size(); ++ i) {
            // 将顺子提取出来
            Cards aScheme = allSeq.at(i);
            // 将提取出来的顺子从用户手中删除
            Cards temp = saveCards;
            temp.remove(aScheme);

            QVector<Cards> seqArray = seqSingle;
            seqArray << aScheme;

            // 继续检测还有没有其它的顺子
            // seqArray存储一轮for循环中多轮递归得到的所有可用的顺子
            // allSeqRecord存储多轮for循环中多轮递归得到的所有可用的顺子
            pickSeqSingles(allSeqRecord, seqArray, temp);
        }
    }
}

// 从集合中筛选最优解的顺子（即：顺子越长，玩家所出牌越多，手牌中的单牌越少，就越可能赢）
QVector<Cards> Strategy::pickOptimalSeqSingles()
{
    QVector<QVector<Cards>> seqRecord;
    QVector<Cards> seqSingles;
    Cards saveCards = m_cards;
    // TODO:
    saveCards.remove(findCardsByCount(4)); // 防止出顺子时，手牌中的炸弹被拆开
    saveCards.remove(findCardsByCount(3)); // 防止出顺子时，手牌中的三张点数相同的牌被拆开
    pickSeqSingles(seqRecord, seqSingles, saveCards);
    if (seqRecord.isEmpty()) {
        return QVector<Cards>(); // 玩家手牌中根本就没有顺子
    }

    QMap<int, int> seqMarks; // key:得到顺子的集合在seqRecord中的位置 value:出完这个顺子之后剩下的单张牌之后的点数之和的
    for (int i = 0; i < seqRecord.size(); ++ i) {
        Cards backupCards = m_cards;
        QVector<Cards> seqArray = seqRecord[i]; // 取出其中一组顺子
        backupCards.remove(seqArray); // 从手牌中移除

        // 判断是否是最合适的顺子
        // 如果剩下的单张牌的数量越少，则所选的顺子组合越合理
        QVector<Cards> singleArray = Strategy(m_player, backupCards).findCardsByCount(1); // 搜索手牌中剩下的单牌

        CardList cardList; // 容器中全是Card类的单牌
        for (int j = 0; j < singleArray.size(); ++ j) {
            cardList << singleArray[j].toCardList(); // 将Cards类型转换为Card类型
        }
        // 找点数相对较大一点的顺子（留下的单牌越小，则所出的顺子越大；留下的单牌越大，则所出的顺子越小）
        int mark = 0;
        for (int j = 0; j < cardList.size(); ++ j) {
            mark += cardList[j].getPoint() + 15; // 如果出现两张单排加起来的点数小于一张单牌，则上述情况不成立。故需要加上15以防止此类情况的发生
        }
        seqMarks.insert(i, mark);
    }

    // 遍历map找到最小的comMark值（剩下单牌的点数和越小，则所出顺子越合理）
    int key = 0;
    int comMark = 10000; // 随意指定的值
    auto it = seqMarks.constBegin();
    for (; it != seqMarks.constEnd(); ++it) {
        if (it.value() < comMark) {
            comMark = it.value();
            key = it.key();
        }
    }

    return seqRecord[key];
}

// 找到指定点数的number张牌
QVector<Cards> Strategy::getCards(Card::CardPoint point, int number)
{
    QVector<Cards> findCardsArray;
    for (Card::CardPoint pt = point; pt < Card::CardPoint::Card_End; pt = static_cast<Card::CardPoint>(pt + 1)) {
        // 为了尽量不拆分别的牌型
        if (m_cards.pointCount(pt) == number) {
            Cards cs = findSamePointCards(pt, number);
            findCardsArray << cs;
        }
    }
    return findCardsArray;
}

// 找到3带1牌或2的牌
QVector<Cards> Strategy::getTripleSingleOrPair(Card::CardPoint begin, PlayHand::HandType type)
{
    // 找到点数相同的牌
    QVector<Cards> findCardArray = getCards(begin, 3);
    if (!findCardArray.isEmpty()) {
        // 将找到的牌从玩家收中删除
        Cards remainCards = m_cards;
        remainCards.remove(findCardArray);;
        // 搜索牌型
        // 搜索单排或者对子
        Strategy st(m_player, remainCards);
        QVector<Cards> cardsArray = st.findCardType(PlayHand(type, Card::CardPoint::Card_Begin, 0), false); // 递归调用一次
        if (!cardsArray.isEmpty()) {
            // 将找到的牌与这三张相同的牌进行组合
            for (int i = 0;  i < findCardArray.size(); ++ i) {
                findCardArray[i].add(cardsArray.at(i));
            }
        } else {
            findCardArray.clear();
        }
    }
    
    return findCardArray;
    
}

// 找到多组飞机
QVector<Cards> Strategy::getPlane(Card::CardPoint begin)
{
    QVector<Cards> findCardArray;
    for (Card::CardPoint point = begin; point <= Card::Card_K; point = static_cast<Card::CardPoint>(point + 1)) {
        // 根据点数和数量进行搜索
        Cards preCards = findSamePointCards(point, 3);
        Cards nextCards = findSamePointCards(static_cast<Card::CardPoint>(point + 1), 3);
        if (!preCards.isEmpty() && !nextCards.isEmpty()) {
            Cards tmp;
            tmp << preCards  << nextCards;
            findCardArray << tmp;
        }
    }
    
    return findCardArray;
}

// 找到多组飞机带1或则2张牌
QVector<Cards> Strategy::getPlane2SingleOr2Pair(Card::CardPoint begin, PlayHand::HandType type)
{
    // 找到飞机
    QVector<Cards> findCardArray = getPlane(begin);
    if (!findCardArray.isEmpty()) {
        // 将找到的牌从用户手中删除
        Cards remainCards = m_cards;
        remainCards.remove(findCardArray);
        // 搜索牌型 （搜索单牌或者成对的牌）
        Strategy st(m_player, remainCards);
        QVector<Cards> cardsArray = st.findCardType(PlayHand(type, Card::CardPoint::Card_Begin, 0), false);
        if (cardsArray.size() >= 2) {
            // 找到了就将其添加到飞机组合中
            for (int i = 0; i < findCardArray.size(); ++ i) {
                Cards tmp;
                tmp << cardsArray[0] << cardsArray[1];
                findCardArray[i].add(tmp);
            }
        } else {
            findCardArray.clear();
        }
    }
    
    return findCardArray;
}

// 找到连对或者顺子
QVector<Cards> Strategy::getSepPairOrSeqSingle(CardInfo &info)
{
    // beat为true, 则找到的类型相同的牌比所出牌大
    QVector<Cards> findCardsArray;
    // 找连对
    if (info.beat) {
        // 最少3个对子， 最大为A
        // 控制搜索的点数
        for (Card::CardPoint point = info.begin; point <= info.end; point = static_cast<Card::CardPoint>(point + 1)) {
            bool found = true;
            Cards seqCards;
            for (int i = 0; i < info.extra; ++ i) { // 控制张数
                // 基于点数和张数进行扑克牌的搜素
                Cards cards = findSamePointCards(static_cast<Card::CardPoint>(point + i), info.number);
                if (cards.isEmpty() || (static_cast<Card::CardPoint>(point + info.extra) >= Card::CardPoint::Card_2)) {
                    // 查找连对失败
                    found = false;
                    seqCards.clear();
                    break;
                } else {
                    seqCards << cards;
                }
            }
            if (found) {
                // 找到一组比其它玩家所出牌大的连对
                findCardsArray << seqCards;
                return findCardsArray;
            }
        }
    } else {
        // beat为false，则对连对的点数与数量无任何要求
        for (Card::CardPoint point = info.begin; point <= info.end; point = static_cast<Card::CardPoint>(point + 1)) {
            /* 先找到最基础的3个连对，再通过组合构成更长的连对
            Cards cards0 = findSamePointCards(point, 2);
            Cards cards1 = findSamePointCards(static_cast<Card::CardPoint>(point + 1), 2);
            Cards cards2 = findSamePointCards(static_cast<Card::CardPoint>(point + 2), 2);
            if (cards0.isEmpty() || cards1.isEmpty() || cards2.isEmpty()) {
                continue;
            }
            */

            // 将找到的最基础的3个连对存储起来，继续查找是否有无更长的连对
            Cards baseSeq = (this->*info.getSeq)(point);
            if (baseSeq.isEmpty()) {
                continue;
            }
            // baseSeq << cards0 << cards1 << cards2;

            // 连对存储到容器中
            findCardsArray << baseSeq;

            int followed = info.base;   // 已有的连对数
            Cards alreadyFollowedCards; // 存储后续找到的更长的连对

            while (true) {
                Card::CardPoint followedPoint = Card::CardPoint(point + followed); // 新的起始点数
                // 判断新的起始点数是否超出上限
                if (followedPoint >= Card::CardPoint::Card_2) { // 新的起始点数超出上限
                    break;
                }
                Cards followedCards = findSamePointCards(followedPoint, info.number);
                if (followedCards.isEmpty()) {
                    break;
                } else {
                    // 组合成更长的连对
                    alreadyFollowedCards << followedCards;
                    Cards newSeq = baseSeq;
                    newSeq << alreadyFollowedCards;
                    findCardsArray << newSeq;
                    ++ followed;
                }
            }
        }
    }

    return findCardsArray;
}

// 找到基础的三张连对
Cards Strategy::getBaseSeqPair(Card::CardPoint point)
{
    Cards baseSeq;
    Cards cards0 = findSamePointCards(point, 2);
    Cards cards1 = findSamePointCards(static_cast<Card::CardPoint>(point + 1), 2);
    Cards cards2 = findSamePointCards(static_cast<Card::CardPoint>(point + 2), 2);
    if (!cards0.isEmpty() && !cards1.isEmpty() && !cards2.isEmpty()) {
        baseSeq << cards0 << cards1 << cards2;
    }

    return baseSeq;
}

// 找到基础的五张顺子
Cards Strategy::getBaseSeqSingle(Card::CardPoint point)
{
    Cards baseSeq;
    Cards cards0 = findSamePointCards(point, 1);
    Cards cards1 = findSamePointCards(static_cast<Card::CardPoint>(point + 1), 1);
    Cards cards2 = findSamePointCards(static_cast<Card::CardPoint>(point + 2), 1);
    Cards cards3 = findSamePointCards(static_cast<Card::CardPoint>(point + 3), 1);
    Cards cards4 = findSamePointCards(static_cast<Card::CardPoint>(point + 4), 1);
    if (!cards0.isEmpty() && !cards1.isEmpty() && !cards2.isEmpty() && !cards3.isEmpty() && !cards4.isEmpty()) {
        baseSeq << cards0 << cards1 << cards2 << cards3 << cards4;
    }

    return baseSeq;
}

QVector<Cards> Strategy::getBomb(Card::CardPoint beginPoint)
{
    QVector<Cards> findCardsArray;
    for (Card::CardPoint point = beginPoint; point < Card::Card_End; point = static_cast<Card::CardPoint>(point + 1)) {
        Cards cards = findSamePointCards(point, 4);
        if (!cards.isEmpty()) {
            findCardsArray << cards;
        }
    }

    return findCardsArray;
}

/*
 // 找到连对或者顺子
QVector<Cards> Strategy::getSepPairOrSeqSingle(Card::CardPoint begin, int extra, bool beat)
{
    // beat为true, 则找到的类型相同的牌比所出牌大
    QVector<Cards> findCardsArray;
    // 找连对
    if (beat) {
        // 最少3个对子， 最大为A
        // 控制搜索的点数
        for (Card::CardPoint point = begin; point <= Card::CardPoint::Card_Q; point = static_cast<Card::CardPoint>(point + 1)) {
            bool found = true;
            Cards seqCards;
            for (int i = 0; i < extra; ++ i) { // 控制张数
                // 基于点数和张数进行扑克牌的搜素
                Cards cards = findSamePointCards(static_cast<Card::CardPoint>(point + 1), 2);
                if (cards.isEmpty() || (static_cast<Card::CardPoint>(point + extra) >= Card::CardPoint::Card_2)) {
                    // 查找连对失败
                    found = false;
                    seqCards.clear();
                    break;
                } else {
                    seqCards << cards;
                }
            }
            if (found) {
                // 找到一组比其它玩家所出牌大的连对
                findCardsArray << seqCards;
                return findCardsArray;
            }
        }
    } else {
        // beat为false，则对连对的点数与数量无任何要求
        for (Card::CardPoint point = begin; point <= Card::CardPoint::Card_Q; point = static_cast<Card::CardPoint>(point + 1)) {
            // 先找到最基础的3个连对，再通过组合构成更长的连对
            Cards cards0 = findSamePointCards(point, 2);
            Cards cards1 = findSamePointCards(static_cast<Card::CardPoint>(point + 1), 2);
            Cards cards2 = findSamePointCards(static_cast<Card::CardPoint>(point + 2), 2);
            if (cards0.isEmpty() || cards1.isEmpty() || cards2.isEmpty()) {
                continue;
            }

            // 将找到的最基础的3个连对存储起来，继续查找是否有无更长的连对
            Cards baseSeq;
            baseSeq << cards0 << cards1 << cards2;

            // 连对存储到容器中
            findCardsArray << baseSeq;

            int followed = 3;   // 已有的连对数
            Cards alreadyFollowedCards; // 存储后续找到的更长的连对

            while (true) {
                Card::CardPoint followedPoint = Card::CardPoint(point + followd); // 新的起始点数
                // 判断新的起始点数是否超出上限
                if (followedPoint >= Card::CardPoint::Card_2) { // 新的起始点数超出上限
                    break;
                }
                Cards followedCards = findSamePointCards(followedPoint, 2);
                if (followCards.isEmpty()) {
                    break;
                } else {
                    // 组合成更长的连对
                    alreadyFollowedCards << followedCards;
                    Cards newSeq = baseSeq;
                    newSeq << alreadyFollowedCards;
                    findCardsArray << newSeq;
                    ++ followed;
                }
            }
        }
    }

    return findCardsArray;
}
*/
